#include "VideoDecoder.h"

VideoDecoder::VideoDecoder(void) : m_thComment(0), m_thInfo(0), m_thSetupInfo(0), m_thDecContext(0)
	, m_bExit(1)
{
	// create fixed image data
	m_lpRawImageData = (unsigned char*)malloc(MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT * 3);

	m_thComment = (th_comment*)malloc(sizeof(th_comment));
	m_thInfo = (th_info*)malloc(sizeof(th_info));
	th_info_init(m_thInfo);
	th_comment_init(m_thComment);
}

VideoDecoder::~VideoDecoder(void)
{
	if (!m_bExit)
	{
		m_bExit = 1;
		while (!isFinished())
			QThread::msleep(10);
		while (m_listPending.size() > 0)
		{
			PacketList *temp = m_listPending.dequeue();
			freePackets(temp);
		}
	}

	th_comment_clear(m_thComment);
	free(m_thComment);
	m_thComment = 0;

	th_info_clear(m_thInfo);
	free(m_thInfo);
	m_thInfo = 0;

	th_decode_free(m_thDecContext);
	m_thDecContext = 0;

	free(m_lpRawImageData);
}

void VideoDecoder::reset(PacketList *headers)
{
	th_info_clear(m_thInfo);
	th_info_init(m_thInfo);
	if (m_thSetupInfo)
		th_setup_free(m_thSetupInfo);
	m_thSetupInfo = 0;

	while (headers && th_decode_headerin(m_thInfo, m_thComment, &m_thSetupInfo, headers->packet) > 0)
		headers = headers->next;
	th_comment_clear(m_thComment);

	if (m_thDecContext)
		th_decode_free(m_thDecContext);
	m_thDecContext = th_decode_alloc(m_thInfo, m_thSetupInfo);
}

int VideoDecoder::decode(PacketList *packets)
{
	PacketList *temp = clonePacket(packets);
	m_listPending.enqueue(temp);

	return 0;
}

void VideoDecoder::run()
{
	m_bExit = 0;
	while (!m_bExit)
	{
		if (m_listPending.size() == 0)
		{
			QThread::msleep(10);
			continue;
		}

		PacketList *packets = m_listPending.dequeue();
		th_ycbcr_buffer buffer;
		ogg_int64_t pos = 0;
		while (packets && 0 == th_decode_packetin(m_thDecContext, packets->packet, &pos))
			packets = packets->next;
		freePackets(packets);

		if (0 == th_decode_ycbcr_out(m_thDecContext, buffer))
		{
			yuv444_to_rgb(buffer, m_lpRawImageData);
			emit onDecoded(buffer[0].width, buffer[0].height);
		}
	}
}

void VideoDecoder::yuv444_to_rgb(th_ycbcr_buffer buffer, unsigned char *rgb)
{
	int h = buffer[0].height;
	int w = buffer[0].width;
	int strike = w * 3;
	for (int i=0; i<h; i++)
	{
		for (int j=0; j<w; j++)
		{
			unsigned char yy = *(buffer[0].data + i*buffer[0].stride + j);
			unsigned char uu = *(buffer[1].data + i*buffer[1].stride + j);
			unsigned char vv = *(buffer[2].data + i*buffer[2].stride + j);
			//*(rgb + i*strike + j * 3 + 2) = (unsigned char)(1.164f*(yy - 16) + 1.596f*(vv - 128));
			//*(rgb + i*strike + j * 3 + 1) = (unsigned char)(1.164f*(yy - 16) - 0.813f*(vv - 128) - 0.391f*(uu - 128));
			//*(rgb + i*strike + j * 3 + 0) = (unsigned char)(1.164f*(yy - 16) + 2.018f*(uu - 128));
			*(rgb + i*strike + j * 3 + 2) = yy + 1.402f * (vv-128);
			*(rgb + i*strike + j * 3 + 1) = yy - 0.34414f * (uu-128) - 0.71414f * (vv-128);
			*(rgb + i*strike + j * 3 + 0) = yy + 1.772f * (uu-128);
		}
	}
}

